#ifndef CIGEOM_GEOMETRY_H
#define CIGEOM_GEOMETRY_H

#include <string>
#include <vector>

#include "Box.h"
#include "../Core/Face.h"

namespace CIView {
    class Scene;
}

namespace CIGeom {
    /**
     * Abstract class that represents the generic geometry rendered in the 3D scene     
     **/
    class Geometry {            
        //Friend classes
        friend class CIView::Scene;

    public:             
        Geometry (const char* n);               //Constructor
        Geometry (const std::string& n);        //Constructor        
        virtual ~Geometry ();                   //Destructor

        //The possible selection mode
        enum {
            NONE
          , VERTICES_SELECTION
          , FACES_SELECTION
        };

    protected:
        std::string name;                               //The geometry name

        CICore::VertexLib vertices;                     //The geometry vertices
        CICore::FaceLib faces;                          //The geometry faces
        Box boundingBox;                                //The geometry bounding box

        //CONSTANTS
        static const CICore::Color VERTEX_SELECTED_COLOR;
        static const CICore::Color FACE_SELECTED_COLOR;
        static const CICore::Color VERTEX_UNSELECTED_COLOR;
        static const CICore::Color FACE_UNSELECTED_COLOR;
        static const CICore::Color FACE_DEFAULT_FLAT_COLOR;
        static const float POINT_SIZE;
        static const float LINE_WIDTH;

    public:             
        bool hasPrimitivesSelected;             //A boolean to indicate if the geometry has at least a primitive selected or not
        bool hasPrimitivesHidden;               //A boolean to indicate if the geometry has at least a primitive hidden or not

        //Utility Methods
        virtual void Render (unsigned int selectionMode) = 0;   //Virtual Method called to render the geometry
        void UpdateBoundingBox();                               //Method called to update the geometry's bounding box

        void ApplyMatrix (const CICore::Matrix& m);             //Virtual Method called to apply a matrix transformation

        void ComputeNormals();                                  //Method called to compute the normal of faces and vertices

        int AddVertex (const float x, const float y, const float z);    //Method called to add a vertex to the geometry vertices
        int AddVertex (CICore::Vertex* v);                              //Method called to add a vertex to the geometry vertices
        void AddFace (CICore::Face* f);                                 //Method called to add a face to the geometry faces

        void DeleteAllVertices();                               //Method called to delete all geometry vertices and faces

        std::string& GetName();                                 //Method called to get a reference to the geometry name
        CICore::FaceLib& GetFaces();                            //Method called to get a reference to the geometry faces
        CICore::VertexLib& GetVertices();                       //Method called to get a reference to the geometry vertices
     
        void SetFaces (CICore::FaceLib& fs);                    //Method called to set the geometry face library
        void SetVertices (CICore::VertexLib& vs);               //Method called to set the geometry vertex library

        void SelectAllVertices();                               //Method called to select all geometry vertices
        void DeselectAllVertices();                             //Method called to deselect all geometry vertices
        void InvertVerticesSelection();                         //Method called to invert the current vertices selection status                
        
        void SelectAllFaces();                                  //Method called to select all geometry faces
        void DeselectAllFaces();                                //Method called to deselect all geometry faces
        void InvertFacesSelection();                            //Method called to invert the current faces selection status    
        
        void HideSelectedVertices();                            //Method called to hide the selected vertices
        void HideSelectedFaces();                               //Method called to hide the selected faces
        void UnhideAll();                                       //Method called to unhide all the primitives

        virtual void LoadNames() = 0;                           //Virtual Method called to load the names that identify this geometry in the OpenGL names stack
        virtual int GetNumberOfNames() = 0;                     //Virtual Method called to get the number of names that identify this geometry 

        virtual void LoadFacesNames() = 0;                      //Virtual Method called to load the faces names in the OpenGL names stack
        virtual void LoadVerticesNames() = 0;                   //Virtual Method called to load the vertices names in the OpenGL names stack

        virtual void SaveAsCI3D (std::ofstream& out) = 0;       //Virtual Method called to save a description of this geometry within an output stream
    };
                    

}
#endif /* CIGEOM_GEOMETRY_H */
